#ifndef __GL_COMPONENT
#define __GL_COMPONENT

#ifdef __linux__
#include <GL/glx.h>
#include <X11/extensions/xf86vmode.h>
#endif        
#include "HiResTimer.h"

//#define PI 3.14159
#define TWO_PI PI*2.0
#define HALF_PI PI/2.0

// Begin - Phase 5
#include "camera.h"
#include "world.h"

#define DUMMY            0x0100 // just a place holder
#define GO_UP            'W'
#define GO_DOWN          'S'
#define GO_RIGHT         'D'
#define GO_LEFT          'A'
#define INVERT_Y         'Y'
#define NEAR_GOD_MODE    'N'
#define CURSOR           'C'

#ifdef _WIN32
#define GO_UP_FAST         VK_SHIFT
#define GO_SHOOT           VK_CONTROL
#define GO_JUMP            VK_SPACE
#define MOUSE_SENSE_UP     VK_ADD
#define MOUSE_SENSE_DOWN   VK_SUBTRACT
#define MOUSE_CENTER_LEFT  VK_LEFT
#define MOUSE_CENTER_RIGHT VK_RIGHT
#define MOUSE_CENTER_UP    VK_UP
#define MOUSE_CENTER_DOWN  VK_DOWN
#define BUTTON_QUIT        VK_ESC
#endif

#ifdef __linux__
#define GO_UP_FAST         XK_Shift_R
#define GO_SHOOT           XK_Control_R
#define GO_JUMP            ' '
#define MOUSE_SENSE_UP     VK_Add
#define MOUSE_SENSE_DOWN   VK_Subtract
#define MOUSE_CENTER_LEFT  XK_Left
#define MOUSE_CENTER_RIGHT XK_Right
#define MOUSE_CENTER_UP    XK_Up
#define MOUSE_CENTER_DOWN  XK_Down
#define BUTTON_QUIT        XK_Escape
#endif
#ifdef __linux__
static int attrListSgl[] =
{
    GLX_RGBA, GLX_RED_SIZE, 4,
    GLX_GREEN_SIZE, 4,
    GLX_BLUE_SIZE, 4,
    GLX_DEPTH_SIZE, 16,
    None
};

/* attributes for a double buffered visual in RGBA format with at least
 * 4 bits per color and a 16 bit depth buffer */
static int attrListDbl[] =
{
    GLX_RGBA, GLX_DOUBLEBUFFER,
    GLX_RED_SIZE, 4,
    GLX_GREEN_SIZE, 4,
    GLX_BLUE_SIZE, 4,
    GLX_DEPTH_SIZE, 16,
    None
};
#endif

class OGLWindow
{
private:
    int yControl;
    bool isCursorVis;
    bool nearGod;
    float m_angle;
	float xAdj; // these help adjust center of screen inconsistency
    float yAdj; // these help adjust center of screen inconsistency
#ifdef __linux__
    GLXContext ctx; //OpenGL drawing context 
#endif
    CHiResTimer *timer;

    // Begin - Phase 5
    CCamera *gameCamera;

    CCamera *OnGetCamera() { return gameCamera; }
    // End - Phase 5
    // Begin - Phase 11
    CWorld *gameWorld;
    CWorld *OnGetWorld() { return gameWorld; }
    // End - Phase 11
#ifdef __linux__
    int KeyPressed(KeySym);
#endif

public:
    bool fullscreen;
    int x, y;
    unsigned int width, height;
    unsigned int depth;

#ifdef __linux__
    Display *dpy; //Which X server are we running on?
    int screen;   //X Servers may have more than one screen
    Window win;   //Window ID
    XSetWindowAttributes attr;
    XF86VidModeModeInfo deskMode;
#endif
#ifdef _WIN32
    HWND       hwnd; // window ID (they call it a handle)
    HDC        hDC; //Windows drawing context
    MSG            msg;
    DWORD        dwExStyle;
    DWORD        dwStyle;
#endif    

    OGLWindow();
    virtual ~OGLWindow();

    void InvertYControl();
    void ToggleNearGod();

    bool Init();
    bool Shutdown();
    bool createGLWindow(char * title, int width, int height, bool fs);
    void ToggleCursor(void);
    int Xevent_loop(void);

    void SetupProjection(int width, int height);
    // Begin - Phase 17 Change parameter lists
    void Prepare();
    void Render(void);
    // End - Phase 17
    // Begin - Phase 6
    int mouseX;
    int mouseY;
    float mouseSensitivity;

    void OnMouseMove(int x, int y);
    // End - Phase 6
    // Begin - Phase 9
    void OnKeyDown(int nVirtKey); 
    // End - Phase 9
    // Begin - Phase 16
    void OnMouseDownR(int x, int y);
    void OnMouseDownL(int x, int y);
    // End - Phase 16
};

#endif
